1 module unde.games.dizzy.omega.bird;
2 
3 import derelict.opengl3.gl;
4 
5 import std.algorithm;
6 import std.conv;
7 import std.math;
8 import std.stdio;
9 import unde.games.dizzy.omega.dizzy;
10 import unde.games.dizzy.omega.main;
11 import unde.games.object;
12 import unde.games.renderer;
13 import unde.games.collision_detector;
14 import unde.games.object;
15 import unde.global_state;
16 
17 class Bird:StaticGameObject
18 {
19     static int num;
20     int number;
21 
22     int hidden;
23     
24     enum SPEED = 0.1;
25     enum G = 0.02;
26     enum MAX_V = 0.3;
27     enum A = 0.01;
28 
29     float def_x, def_y, def_z;
30     float dx = 0.0, dy = 0.0;
31     float rx;
32 
33     int fly;
34 
35     float[7][3] flame_coords;
36 
37     Dizzy the_hero;
38 
39     bool search_surface;
40     static GLuint rope_texture;
41     ulong delay;
42 
43     this(MainGameObject root, float[3] coords, float rx, Dizzy hero, ulong delay = 0)
44     {
45         def_x = x = coords[0];
46         def_y = y = coords[1];
47         def_z = z = coords[2];
48         this.rx = rx;
49         this.delay = delay;
50         the_hero = hero;
51         number = num++;
52         models["bird"] = root.models["bird"];
53         models["flame"] = root.models["flame"];
54         dx = SPEED;
55 
56         collision_objects["solid"] = root.collision_objects["solid"];
57         super(root);
58     }
59 
60     void start_fly()
61     {
62         fly = 1;
63     }
64 
65     void fall()
66     {
67         fly = 2;
68     }
69 
70     bool fly_anim(GlobalState gs, string name)
71     {
72         float f = (frame*4)%240;
73         float degree = 0.0;
74         float translate = 0.0;
75         
76         if (f < 120.0)
77             translate = 0.2 - 0.4*f/120.0;
78         else if (f < 240.0)
79             translate = -0.2 + 0.4*(f - 120.0)/120.0;
80 
81         if (f < 120.0)
82             degree = f/2 - 30.0;
83         else if (f < 240.0)
84             degree = 30.0 - (f/2 - 60.0);
85 
86         glTranslatef(0.0, translate, 0.0);
87         
88         if (name == "BirdLeftWing")
89         {
90             glRotatef(degree, -1.0, 0.0, 0.0);
91         }
92         
93         if (name == "BirdRightWing")
94         {
95             glRotatef(-degree, -1.0, 0.0, 0.0);
96         }
97         
98         return true;
99     }
100 
101     void hide()
102     {
103         hidden++;
104     }
105 
106     override void draw(GlobalState gs)
107     {
108         if ( abs(root.scrx-x) > 32.0 &&
109              abs(root.scry-y) > 18.0 )
110             return;
111 
112         if (!hidden)
113         {
114             glPushMatrix();
115             glTranslatef(x, y, z);
116             glRotatef(atan2(dy, dx)*180/PI,0,1,0);
117             recursive_render(gs, models["bird"], &fly_anim);
118             glPopMatrix();
119 
120             foreach(flame; flame_coords)
121             {
122                 if (!flame[0].isNaN())
123                 {
124                     glPushMatrix();
125                     glTranslatef(flame[0], flame[1], flame[2]);
126                     glScalef(flame[3], flame[3], flame[3]);
127                     recursive_render(gs, models["flame"]);
128                     glPopMatrix();
129                 }
130             }
131         }
132     }
133 
134     override bool tick(GlobalState gs)
135     {
136         if ( hidden || abs(root.scrx-x) > 32.0 &&
137                 abs(root.scry-y) > 18.0 )
138             return true;
139 
140         frame++;
141 
142         if (frame < delay) return true;
143         
144         x += dx;
145         y += dy;
146 
147         if (the_hero is null) return true;        
148 
149         foreach (ref flame; flame_coords)
150         {
151             if (!flame[0].isNaN())
152             {
153                 flame[0..3] += flame[4..7];
154                 flame[3] += 0.02;
155 
156                 if (abs(the_hero.x - flame[0]) < 1.5 &&
157                     flame[1] > the_hero.y &&
158                     flame[1] < the_hero.y+2.5)
159                 {
160                     the_hero.energy -= 1;
161                     if (the_hero.energy <= 0.0)
162                     {
163                         the_hero.die("Flame");
164                     }
165                 }
166             }
167         }
168 
169         if (!flame_coords[0][0].isNaN() && 
170              flame_coords[0][3] > 1.0)
171         {
172             flame_coords[2] = flame_coords[1];
173             flame_coords[1] = flame_coords[0];
174             flame_coords[0] = flame_coords[0].init;
175         }
176         else if (!flame_coords[1][0].isNaN() && 
177              flame_coords[1][3] > 1.5)
178         {
179             flame_coords[2] = flame_coords[1];
180             flame_coords[1] = flame_coords[1].init;
181         }
182         else if (!flame_coords[2][0].isNaN() && 
183              flame_coords[2][3] > 2.0)
184         {
185             flame_coords[2] = flame_coords[2].init;
186         }
187 
188         if ((dx > 0 && the_hero.x > (x+3.0) &&
189             the_hero.x - (x+3.0) < 7.0 ||
190              dx < 0 && the_hero.x < (x-3.0) &&
191             (x-3.0) - the_hero.x < 7.0) &&
192             abs(the_hero.y - y) < 3.0 )
193         {
194             if (flame_coords[0][0].isNaN())
195             {
196                 flame_coords[0] = [x + dx*36, y, z,
197                     0.5, 2*dx, 2*dy, 0];
198             }
199         }
200 
201         if (fly == 1)
202         {
203             dx = the_hero.x - x;
204             dy = the_hero.y+2.0 - y;
205             float l = sqrt(dx^^2 + dy^^2);
206             float s = SPEED * (l/20.0);
207             if (s > 2.0*SPEED) s = 2.0*SPEED;
208             if (s < 0.5*SPEED) s = 0.5*SPEED;
209             l /= s;
210             dx /= l;
211             dy /= l;
212             z = -5.0;
213         }
214         else if (fly == 2)
215         {
216             dy -= G;
217             if (dy < -MAX_V) dy = -MAX_V;
218 
219             float x0 = x-0.5;
220             float x1 = x+0.5;
221             float y0 = y-0.5;
222             float y1 = y+0.5;
223             float z0 = z-8.0;
224             float z1 = z+8.0;
225 
226             auto mb = if_intersect (collision_objects["solid"], [x0, y0, z0, x1, y1, z1]);
227             if (mb > 0 || y < -6.0)
228             {
229                 DizzyOmega dz = cast(DizzyOmega) root;
230                 dz.bird_item.x = x;
231                 dz.bird_item.y = y;
232                 dz.bird_item.z = 0;
233                 dz.track = 1;
234                 dz.play_music();
235                 hide();
236             }
237         }
238         else
239         {
240             if (x > rx)
241                 dx = -SPEED;
242             if (x < def_x)
243                 dx = SPEED;
244         }
245 
246         return true;
247     }    
248 
249     override void load(string[string] s)
250     {
251         string p = "bird"~number.to!(string);
252         if (p~"-x" in s)
253             x = s[p~"-x"].to!(float);
254         else
255             x = def_x;
256             
257         if (p~"-y" in s)
258             y = s[p~"-y"].to!(float);
259         else
260             y = def_y;
261             
262         if (p~"-z" in s)
263             z = s[p~"-z"].to!(float);
264         else
265             z = def_z;
266 
267         if (p~"-dx" in s)
268             dx = s[p~"-dx"].to!(float);
269         else
270             dx = SPEED;
271 
272         if (p~"-dy" in s)
273             dy = s[p~"-dy"].to!(float);
274         else
275             dy = 0.0;
276 
277         if (p~"-fly" in s)
278             fly = s[p~"-fly"].to!(int);
279         else
280             fly = 0;
281 
282         frame = 0;
283 
284         if (p in s)
285         {
286             hidden = (s[p] == "hidden")?1:0;
287         }
288         else
289         {
290             hidden = 0;
291         }
292     }
293 
294     override void save(ref string[string] s)
295     {
296         string p = "bird"~number.to!(string);
297         if (hidden == 1)
298             s[p] = "hidden";
299         if (fly > 0)
300             s[p~"-fly"] = fly.to!(string);
301 
302         s[p~"-x"] = x.to!(string);
303         s[p~"-y"] = y.to!(string);
304         s[p~"-z"] = z.to!(string);
305         s[p~"-dx"] = dx.to!(string);
306         s[p~"-dy"] = dy.to!(string);
307         s[p~"-state"] = state.to!(string);
308     }    
309 }
310